package io.mft.flow.core.executable.builder;

import java.util.ArrayList;
import java.util.List;

import io.mft.flow.core.FlowExecutor;
import io.mft.flow.core.executable.Chain;
import io.mft.flow.core.executable.Condition;
import io.mft.flow.core.executable.ConditionExecutable;
import io.mft.flow.core.executable.ConditionType;
import io.mft.flow.core.executable.ExecutableType;
import io.mft.flow.core.executable.condition.AsyncCondition;
import io.mft.flow.core.executable.condition.SyncCondition;
import io.mft.flow.core.executable.condition.SyncWaitAsyncCondition;
import io.mft.flow.core.executable.drive.ChainConditionDriver;
import lombok.AllArgsConstructor;

public class ChainBuilder {
	private Chain chain;
	private String chainId;
	private FlowExecutor flowExecutor;
	private List<ChainConditionExecutableWraper> chainConditionExecutableWrapers = new ArrayList<>();
	private List<Condition> conditionList = new ArrayList<>();
	public ChainBuilder build() {
		chainConditionExecutableWrapers.forEach(w -> {
			List<ConditionExecutable> chainNodeList = new ArrayList<>();
			for (int i = 0; i < w.nodeIds.length; i++) {
				String nodeId = w.nodeIds[i];
				String uniqueId = chainId + "." + w.pos + "." + i + "." + nodeId;
				ConditionExecutable nodeConditionExecutable = new ConditionExecutable(uniqueId, nodeId,w.executableType);
				chainNodeList.add(nodeConditionExecutable);
			}
			switch (w.conditionType) {
			case sync:
				SyncCondition sysCondition = new SyncCondition(w.driver, chainNodeList);
				sysCondition.setFlowExecutor(flowExecutor);
				conditionList.add(sysCondition);
				break;
			case syncWaitAsync:
				SyncWaitAsyncCondition syncWaitAsyncCondition = new SyncWaitAsyncCondition(chainNodeList);
				syncWaitAsyncCondition.setFlowExecutor(flowExecutor);
				conditionList.add(syncWaitAsyncCondition);
				break;
			case async:
				AsyncCondition asyncCondition = new AsyncCondition(chainNodeList);
				asyncCondition.setFlowExecutor(flowExecutor);
				conditionList.add(asyncCondition);
				break;
			default:
				break;
			}
		});
		chain = new Chain(chainId, conditionList);
		return this;
	}

	public void addToFlowExecutor(boolean isReload) {
		flowExecutor.addChain(chain,isReload);
	}

	public ChainBuilder(String chainId, FlowExecutor flowExecutor) {
		this.flowExecutor = flowExecutor;
		this.chainId=chainId;
	}

	@AllArgsConstructor
	class ChainConditionExecutableWraper {
		private ConditionType conditionType;
		private int pos;
		private ChainConditionDriver driver;
		private String[] nodeIds;
		private ExecutableType executableType;
	}

	public ChainBuilder addChainConditionExecutable(ExecutableType executableType,ConditionType conditionType, int pos, ChainConditionDriver driver,
			String... nodeIds) {
		ChainConditionExecutableWraper chainConditionExecutableWraper = new ChainConditionExecutableWraper(
				conditionType, pos, driver, nodeIds,executableType);
		chainConditionExecutableWrapers.add(chainConditionExecutableWraper);
		return this;
	}
}
